package com.own.component.netty.handler;

import com.alibaba.fastjson2.JSON;
import com.own.component.netty.constant.ConstantCommon;
import com.own.component.netty.model.RequestModel;
import com.own.component.netty.util.NettyUtil;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketCloseStatus;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * WebsocketMessageHandler
 *
 * @author chenxueli
 * @date 2021/4/9 9:34
 */
@Slf4j
@Sharable
@Component
public class NettyMessageHandler extends SimpleChannelInboundHandler<WebSocketFrame> {

    @Override
    protected void channelRead0(ChannelHandlerContext context, WebSocketFrame message) {
        if (message instanceof TextWebSocketFrame) {
            var channel = context.channel();
            var data = ((TextWebSocketFrame) message).text();
            // 解析数据，会有请求的路径信息
            var model = handleText(context, data);
            if (model.getAction().startsWith(ConstantCommon.HEART)) {
                NettyUtil.send(channel, ConstantCommon.HEART + ConstantCommon.RESPONSE_SPLIT + System.currentTimeMillis());
                return;
            }
            var method = MethodMap.getMethod(model.getAction());
            if (method != null) {
                try {
                    var responseText = handle(method, model);
                    NettyUtil.send(channel, Objects.requireNonNullElseGet(responseText, () -> "void" + ConstantCommon.RESPONSE_SPLIT + model.getCallback()));
                } catch (Exception e) {
                    NettyUtil.send(channel, "/500" + ConstantCommon.RESPONSE_SPLIT + model.getCallback() + ConstantCommon.RESPONSE_SPLIT + "消息处理异常");
                }
            } else {
                NettyUtil.send(channel, "/404" + ConstantCommon.RESPONSE_SPLIT + model.getCallback() + ConstantCommon.RESPONSE_SPLIT + "消息处理方法未找到");
            }
        } else {
            // 不接受文本以外的数据帧类型
            context.channel().writeAndFlush(WebSocketCloseStatus.INVALID_MESSAGE_TYPE).addListener(ChannelFutureListener.CLOSE);
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext context) throws Exception {
        super.channelInactive(context);
        var channel = context.channel();
        ChannelMap.MAP.remove(channel.id().asLongText());
        log.info("链接断开：{}", context.channel().remoteAddress());
    }

    @Override
    public void channelActive(ChannelHandlerContext context) throws Exception {
        super.channelActive(context);
        var channel = context.channel();
        ChannelMap.MAP.put(channel.id().asLongText(), channel);
        log.info("链接创建：{}，id：{}", context.channel().remoteAddress(), context.channel().id().asShortText());
    }

    private RequestModel handleText(ChannelHandlerContext context, String data) {
        // 解析数据，会有请求的路径信息
        var index = data.indexOf("{");
        var callback = data.substring(0, index);
        // 强解析请求路径
        var action = callback.substring(0, callback.length() - 13);
        return RequestModel.builder()
                .id(context.channel().id().asLongText())
                .action(action)
                .callback(callback)
                .data(data.substring(index))
                .build();
    }

    /**
     * 处理消息的方法
     *
     * @param method 消息发方法
     * @param model  消息对象
     * @return 返回内容
     * @throws InvocationTargetException 异常信息
     * @throws IllegalAccessException    异常信息
     */
    public String handle(Method method, RequestModel model) throws InvocationTargetException, IllegalAccessException {
        var bean = MethodMap.getBean(model.getAction());
        var length = method.getParameters().length;
        var parameters = new DefaultParameterNameDiscoverer().getParameterNames(method);
        if (length == 0 || parameters == null) {
            if (ConstantCommon.DEFAULT_RETURN.equals(method.getReturnType().getName())) {
                method.invoke(bean);
                return null;
            }
            return model.getCallback() + ConstantCommon.RESPONSE_SPLIT + JSON.toJSONString(method.invoke(bean));
        }
        // 获取所有的方法内的参数，进行强行解析
        var jsonObject = JSON.parseObject(model.getData());
        // 获取用户信息
        var params = new Object[length];
        for (int i = 0; i < length; i++) {
            var parameter = method.getParameters()[i];
            var clazz = parameter.getType();
            // 如果当前对象中没有值
            params[i] = jsonObject.containsKey(parameters[i])
                    ? jsonObject.getObject(parameters[i], clazz)
                    : JSON.parseObject(model.getData(), clazz);
        }
        if (ConstantCommon.DEFAULT_RETURN.equals(method.getReturnType().getName())) {
            method.invoke(bean, params);
            return null;
        }
        return model.getCallback() + ConstantCommon.RESPONSE_SPLIT + JSON.toJSONString(method.invoke(bean, params));
    }

}
